import { _decorator, Component, Node, Vec3, math } from 'cc';

const { ccclass, property } = _decorator;

const LOG_INTERVAL = 0.2;

@ccclass('CameraFollow')
export class CameraFollow extends Component {
  @property(Node)
  public target: Node | null = null;

  @property
  public lerp = 0.2; // 0~1, higher is snappier; 1 locks directly.

  @property
  public snapThreshold = 0.05; // world units

  @property
  public pixelSnap = true;

  private tmp = new Vec3();
  private logTimer = 0;

  onEnable() {
    if (typeof console !== 'undefined' && console.debug) {
      const id = (this.target as any)?.uuid ?? 'null';
      console.debug('[CAM] follow target=', id);
    }
    this.logTimer = 0;
  }

  setTarget(n: Node) {
    this.target = n;
    if (typeof console !== 'undefined' && console.debug) {
      console.debug('[CAM] follow target=', (n as any)?.uuid ?? 'null');
    }
  }

  public bootstrap(target: Node) {
    this.setTarget(target);
    this.logTimer = 0;
  }

  update(dt: number) {
    try {
      if (!this.target) return;
      this.logTimer += dt;
      const cur = this.node.worldPosition;
      const dst = this.target.worldPosition;
      const base = math.clamp01(this.lerp);
      const scaled = base >= 1 ? 1 : 1 - Math.pow(1 - base, Math.max(0, dt * 60));
      const t = math.clamp01(scaled);
      const dx = dst.x - cur.x;
      const dy = dst.y - cur.y;
      let nx: number;
      let ny: number;
      if (Math.abs(dx) <= this.snapThreshold && Math.abs(dy) <= this.snapThreshold) {
        nx = dst.x;
        ny = dst.y;
      } else {
        nx = math.lerp(cur.x, dst.x, t);
        ny = math.lerp(cur.y, dst.y, t);
      }
      if (this.pixelSnap) {
        const snappedX = Math.round(nx);
        const snappedY = Math.round(ny);
        nx = snappedX;
        ny = snappedY;
      }
      this.tmp.set(nx, ny, cur.z);
      this.node.setWorldPosition(this.tmp);

      if (this.logTimer >= LOG_INTERVAL) {
        this.logTimer = 0;
        if (typeof console !== 'undefined' && console.debug) {
          console.debug(
            `[CAM] follow x=${nx.toFixed(2)} y=${ny.toFixed(2)} snap=${this.pixelSnap ? 'true' : 'false'}`,
          );
        }
      }
    } catch (err) {
      if (typeof console !== 'undefined' && console.error) {
        console.error('[BOOT-ERROR]', err);
      }
      throw err;
    }
  }
}

export default CameraFollow;

export function bootstrapCameraFollow(follow: CameraFollow, target: Node) {
  console.log('[CAM] bootstrap...');
  follow.bootstrap(target);
}
